#pragma once 

/* ES数据管理的相关操作 */

#include "icsearch.hpp"
#include "user.hxx"
#include "message.hxx"

namespace ChatSystem
{
    class EsClientFactory
    {
    public:
        static std::shared_ptr<elasticlient::Client> create(const std::vector<std::string>& host_list)
        {
            return std::make_shared<elasticlient::Client>(host_list);
        }
    private:
    };

    //ES数据管理
    class ESUser
    {
    public:
        using ptr = std::shared_ptr<ESUser>;
        ESUser(const std::shared_ptr<elasticlient::Client>& es_client)
        :_es_client(es_client)
        {}
        ~ESUser(){}

        //创建用户索引
        bool createIndex()
        {
            bool ret = ChatSystem::ESIndex(_es_client, "user")
            .append(_uid_key, _keyword, _standard, true)
            .append(_nickname_key)
            .append(_phone_key, _keyword, _standard, true)
            .append(_desc_key, "text", _standard, false)
            .append(_avatar_id_key, _keyword, _standard, false)
            .create();
            if(ret == false)
            {
                LOG_INFO("用户信息索引创建失败！");
                return false;
            }
            LOG_INFO("用户信息索引创建成功！");
            return true;
        }
        //新增数据/更新数据
        bool appendData(const std::string& uid,
            const std::string& nickname, 
            const std::string& phone = "",
            const std::string& description = "",
            const std::string& avatar_id = "")
        {
            //新增数据
            bool ret = ChatSystem::ESInsert(_es_client, "user")
            .append(_uid_key, uid)
            .append(_phone_key, phone)
            .append(_nickname_key, nickname)
            .append(_desc_key, description)
            .append(_avatar_id_key, avatar_id)
            .insert(uid);
            if(ret == false)
            {
                LOG_ERROR("用户数据插入/更新失败！");
                return false;
            }
            LOG_INFO("用户数据插入/更新成功！");
            return true;
        }
        //搜索用户
        std::vector<ChatSystem::User> search(const std::string& key, const std::vector<std::string>& uid_list)
        {
            //查询数据
            std::vector<ChatSystem::User> ret;
            Json::Value res = ChatSystem::ESSearch(_es_client, "user")
            .append_should_match("phone.keyword", key)  //"phone.keyword" 表示是一个关键字，不能对其分词
            .append_should_match("user_id.keyword", key) //"user_id.keyword" 表示是一个关键字，不能对其分词
            .append_should_match(_nickname_key, key)
            .append_must_not_terms("user_id.keyword", uid_list)
            .search();
            if(res.isArray() == false)
            {
                LOG_ERROR("用户搜索结果为空，或者结果不是数组类型!");
                return ret;
            }
            int sz = res.size();
            for(int i = 0; i < sz; ++i)
            {
                ChatSystem::User user;
                user.user_id(res[i][_source][_uid_key].asString());
                user.nickname(res[i][_source][_nickname_key].asString());
                user.description(res[i][_source][_desc_key].asString());
                user.phone(res[i][_source][_phone_key].asString());
                user.avatar_id(res[i][_source][_avatar_id_key].asString());
                ret.push_back(user);
            }
            return ret;
        }
    private:
        //这样定义是为了防止在几个固定字符串的位置写的一样，不好排查
        const std::string _uid_key = "user_id";         
        const std::string _nickname_key = "nickname";
        const std::string _desc_key = "description";
        const std::string _phone_key = "phone";
        const std::string _avatar_id_key = "avatar_id";
        const std::string _source = "_source";
        const std::string _keyword = "keyword";
        const std::string _standard = "standard";

        std::shared_ptr<elasticlient::Client> _es_client;
    };


    class ESMessage
    {
    public:
        using ptr = std::shared_ptr<ESMessage>;
        ESMessage(const std::shared_ptr<elasticlient::Client>& es_client)
        :_es_client(es_client)
        {}
        ~ESMessage(){}

        //创建消息索引
        bool createIndex()
        {
            bool ret = ChatSystem::ESIndex(_es_client, "message")
            .append(_chat_session_id, _keyword, _standard)
            .append(_message_id, _keyword, _standard, false)
            .append(_uid_key, _keyword, _standard, false)
            .append(_create_time, "long", _standard, false)
            .append(_content)
            .create();
            if(ret == false)
            {
                LOG_INFO("消息信息索引创建失败！");
                return false;
            }
            LOG_INFO("消息信息索引创建成功！");
            return true;
        }
        //新增数据/更新数据
        bool appendData(const std::string& uid,
            const std::string& message_id, 
            const long create_time,
            const std::string& chat_session_id,
            const std::string& content)
        {
            //新增数据
            bool ret = ChatSystem::ESInsert(_es_client, "message")
            .append(_uid_key, uid)
            .append(_message_id, message_id)
            .append(_create_time, create_time)
            .append(_chat_session_id, chat_session_id)
            .append(_content, content)
            .insert(uid);
            if(ret == false)
            {
                LOG_ERROR("消息数据插入/更新失败！");
                return false;
            }
            LOG_INFO("消息数据插入/更新成功！");
            return true;
        }
        //搜索消息
        std::vector<ChatSystem::Message> search(const std::string& key, const std::string& chat_session_id)
        {
            //查询数据
            std::vector<ChatSystem::Message> ret;
            Json::Value res = ChatSystem::ESSearch(_es_client, "message")
            .append_must_terms("chat_session_id.keyword", {chat_session_id})  
            .append_must_match("content", {key})  
            .search();
            if(res.isArray() == false)
            {
                LOG_ERROR("消息搜索结果为空，或者结果不是数组类型!");
                return ret;
            }
            int sz = res.size();
            for(int i = 0; i < sz; ++i)
            {
                ChatSystem::Message msg;
                msg.user_id(res[i][_source][_uid_key].asString());
                msg.message_id(res[i][_source][_message_id].asString());
                msg.chat_session_id(res[i][_source][_chat_session_id].asString());
                msg.create_time(boost::posix_time::from_time_t(res[i][_source][_create_time].asInt64()));
                msg.content(res[i][_source][_content].asString());
                ret.push_back(msg);
            }
            return ret;
        }

        //删除消息表中的消息
        bool remove(std::string& session_id)
        {
            bool ret = ESRemove(_es_client, "message")
            .remove(session_id);
            if(ret == false)
            {
                LOG_ERROR("消息数据删除失败！");
                return false;
            }
            LOG_INFO("消息数据删除成功！");
            return true;
        }
    private:
        //这样定义是为了防止在几个固定字符串的位置写的一样，不好排查
        const std::string _chat_session_id = "chat_session_id";
        const std::string _message_id = "message_id";
        const std::string _uid_key = "user_id";
        const std::string _create_time = "create_time";
        const std::string _content = "content";
        const std::string _source = "_source";
        const std::string _keyword = "keyword";
        const std::string _standard = "standard";


        std::shared_ptr<elasticlient::Client> _es_client;
    };

}